package io.github.echarts.model.series;

import io.github.echarts.model.coordinate.CoordinateSystem;
import io.github.echarts.model.coordinate.DataRange;
import io.github.echarts.option.series.BarSeries;
import io.github.echarts.option.style.ItemStyle;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 柱状图系列模型的默认实现
 */
public class DefaultBarSeriesModel implements BarSeriesModel {
    
    /**
     * 柱状图配置选项
     */
    private BarSeries option;
    
    /**
     * 坐标系ID
     */
    private String coordinateSystemId;
    
    /**
     * 系列索引
     */
    private int seriesIndex;
    
    /**
     * 数据项
     */
    private List<BarDataItem> dataItems;
    
    /**
     * 数据范围
     */
    private DataRange dataRange;
    
    /**
     * 堆叠基准值（针对堆叠柱状图）
     */
    private double[] stackedBaseline;
    
    /**
     * 默认柱条宽度
     */
    private static final int DEFAULT_BAR_WIDTH = 20;
    
    /**
     * 默认柱条间距（相对于宽度的百分比）
     */
    private static final double DEFAULT_BAR_GAP_PERCENT = 0.3;
    
    /**
     * 默认柱条最小高度
     */
    private static final int DEFAULT_BAR_MIN_HEIGHT = 0;
    
    /**
     * 默认颜色数组
     */
    private static final String[] DEFAULT_COLORS = {
        "#5470c6", // 蓝色
        "#91cc75", // 绿色
        "#fac858", // 黄色
        "#ee6666", // 红色
        "#73c0de", // 浅蓝色
        "#3ba272", // 深绿色
        "#fc8452", // 橙色
        "#9a60b4", // 紫色
        "#ea7ccc"  // 粉色
    };

    /**
     * 坐标系实例
     */
    private CoordinateSystem coordinateSystem;

    /**
     * 柱状图数据项类，存储单个数据点的信息
     */
    public static class BarDataItem {
        /**
         * 数据值
         */
        private double value;
        
        /**
         * 类别名称（X轴对应的类别）
         */
        private Object category;
        
        /**
         * 自定义样式
         */
        private ItemStyle itemStyle;
        
        /**
         * 构造函数
         * 
         * @param category 类别
         * @param value 数据值
         */
        public BarDataItem(Object category, double value) {
            this.category = category;
            this.value = value;
        }
        
        /**
         * 获取数据值
         * 
         * @return 数据值
         */
        public double getValue() {
            return value;
        }
        
        /**
         * 设置数据值
         * 
         * @param value 数据值
         */
        public void setValue(double value) {
            this.value = value;
        }
        
        /**
         * 获取类别
         * 
         * @return 类别对象
         */
        public Object getCategory() {
            return category;
        }
        
        /**
         * 获取项目样式
         * 
         * @return 项目样式
         */
        public ItemStyle getItemStyle() {
            return itemStyle;
        }
        
        /**
         * 设置项目样式
         * 
         * @param itemStyle 项目样式
         */
        public void setItemStyle(ItemStyle itemStyle) {
            this.itemStyle = itemStyle;
        }
    }
    
    /**
     * 构造函数
     * 
     * @param option 柱状图配置选项
     * @param coordinateSystemId 坐标系ID
     */
    public DefaultBarSeriesModel(BarSeries option, String coordinateSystemId) {
        this.option = option;
        this.coordinateSystemId = coordinateSystemId;
        this.dataItems = new ArrayList<>();
        this.dataRange = new DataRange(0, 0);
    }
    
    /**
     * 默认构造函数
     */
    public DefaultBarSeriesModel() {
        this.dataItems = new ArrayList<>();
        this.dataRange = new DataRange(0, 0);
    }

    @Override
    public String getType() {
        return "bar";
    }

    @Override
    public String getName() {
        return option != null ? option.getName() : "";
    }

    @Override
    public String getCoordinateSystemId() {
        return coordinateSystemId;
    }
    
    /**
     * 设置坐标系ID
     * 
     * @param coordinateSystemId 坐标系ID
     */
    public void setCoordinateSystemId(String coordinateSystemId) {
        this.coordinateSystemId = coordinateSystemId;
    }
    
    /**
     * 设置选项
     * 
     * @param option 柱状图配置选项
     */
    public void setOption(BarSeries option) {
        this.option = option;
    }
    
    @Override
    public int getSeriesIndex() {
        return seriesIndex;
    }
    
    @Override
    public void setSeriesIndex(int index) {
        this.seriesIndex = index;
    }
    
    @Override
    public String getStack() {
        return option != null && option.getStack() != null ? option.getStack() : null;
    }
    
    @Override
    public String getStackId() {
        return getStack();
    }
    
    @Override
    public boolean isStacked() {
        return getStack() != null && !getStack().isEmpty();
    }
    
    @Override
    public int getBarWidth() {
        return option != null && option.getBarWidth() != null ? option.getBarWidth() : DEFAULT_BAR_WIDTH;
    }
    
    @Override
    public int getBarGap() {
        return option != null && option.getBarGap() != null ? option.getBarGap() : (int)(getBarWidth() * DEFAULT_BAR_GAP_PERCENT);
    }
    
    @Override
    public int getBarMinHeight() {
        return option != null && option.getBarMinHeight() != null ? Integer.parseInt(option.getBarMinHeight()) : DEFAULT_BAR_MIN_HEIGHT;
    }

    /**
     * 将Object安全地转换为Object[]数组
     * 
     * @param data 可能是数组的对象
     * @return 转换后的Object[]数组，如果无法转换则返回空数组
     */
    private Object[] toObjectArray(Object data) {
        if (data == null) {
            return new Object[0];
        }
        
        // 如果已经是Object[]，直接返回
        if (data instanceof Object[]) {
            return (Object[]) data;
        }
        
        // 如果是其他类型的数组，转换为Object[]
        if (data.getClass().isArray()) {
            int length = Array.getLength(data);
            Object[] result = new Object[length];
            for (int i = 0; i < length; i++) {
                result[i] = Array.get(data, i);
            }
            return result;
        }
        
        // 如果是列表，转换为Object[]
        if (data instanceof List) {
            List<?> list = (List<?>) data;
            return list.toArray(new Object[0]);
        }
        
        // 将单个对象包装为数组
        return new Object[] { data };
    }

    @Override
    public void processData() {
        // 处理原始数据，将配置数据转换为内部数据结构
        if (option == null) {
            return;
        }
        
        // 安全地将option.getData()转换为Object[]
        Object[] rawData = toObjectArray(option.getData());
        if (rawData.length == 0) {
            return;
        }
        
        dataItems.clear();
        
        // 解析不同格式的数据
        for (int i = 0; i < rawData.length; i++) {
            Object data = rawData[i];
            
            if (data instanceof Number) {
                // 简单数值类型，使用索引作为类别
                dataItems.add(new BarDataItem(i, ((Number) data).doubleValue()));
            } else if (data instanceof Map) {
                // Map类型，包含值和其他属性
                @SuppressWarnings("unchecked")
                Map<String, Object> dataMap = (Map<String, Object>) data;
                
                Object value = dataMap.get("value");
                Object name = dataMap.get("name");
                Object itemStyle = dataMap.get("itemStyle");
                
                if (value instanceof Number) {
                    BarDataItem item = new BarDataItem(
                            name != null ? name : i, 
                            ((Number) value).doubleValue());
                    
                    // 设置自定义样式（如果有）
                    if (itemStyle instanceof ItemStyle) {
                        item.setItemStyle((ItemStyle) itemStyle);
                    }
                    
                    dataItems.add(item);
                }
            } else {
                // 其他类型，尝试转换为数值
                try {
                    double value = Double.parseDouble(data.toString());
                    dataItems.add(new BarDataItem(i, value));
                } catch (NumberFormatException e) {
                    // 忽略无法转换为数值的数据
                }
            }
        }
        
        // 计算数据范围
        calculateDataRange();
    }
    
    /**
     * 计算数据范围
     */
    private void calculateDataRange() {
        if (dataItems.isEmpty()) {
            dataRange = new DataRange(0, 0);
            return;
        }
        
        double min = Double.MAX_VALUE;
        double max = Double.MIN_VALUE;
        
        // 找出最小值和最大值
        for (BarDataItem item : dataItems) {
            double value = item.getValue();
            min = Math.min(min, value);
            max = Math.max(max, value);
        }
        
        // 处理特殊情况：所有值都相同
        if (min == max) {
            if (min == 0) {
                // 如果值都是0，设置范围为0-1
                min = 0;
                max = 1;
            } else {
                // 否则，在值的基础上下浮动一定比例
                double delta = Math.abs(min * 0.1);
                min = min - delta;
                max = max + delta;
            }
        }
        
        // 确保正数据从0开始
        if (min > 0) {
            min = 0;
        }
        
        // 创建数据范围对象
        dataRange = new DataRange(min, max);
    }
    
    /**
     * 设置堆叠基准值数组
     * 
     * @param baseline 基准值数组
     */
    public void setStackedBaseline(double[] baseline) {
        this.stackedBaseline = baseline;
    }
    
    /**
     * 获取堆叠基准值数组
     * 
     * @return 基准值数组
     */
    public double[] getStackedBaseline() {
        return stackedBaseline;
    }

    @Override
    public DataRange getDataRange() {
        return dataRange;
    }
    
    /**
     * 获取数据范围值数组
     * 
     * @return 包含最小值和最大值的数组
     */
    @Override
    public double[] getDataRangeValues() {
        return new double[] { dataRange.getMin(), dataRange.getMax() };
    }
    
    /**
     * 获取颜色
     * 
     * @return 颜色
     */
    public String getColor() {
        int index = getSeriesIndex();
        // 使用默认颜色数组，循环使用
        return DEFAULT_COLORS[index % DEFAULT_COLORS.length];
    }
    
    /**
     * 获取数值数据列表
     * 
     * @return 数值列表
     */
    public List<Double> getNumericData() {
        List<Double> result = new ArrayList<>(dataItems.size());
        for (BarDataItem item : dataItems) {
            result.add(item.getValue());
        }
        return result;
    }
    
    /**
     * 获取数据项列表
     * 
     * @return 数据项列表
     */
    public List<BarDataItem> getDataItems() {
        return dataItems;
    }

    /**
     * 获取Z轴层级
     * 
     * @return Z轴层级值
     */
    @Override
    public int getZLevel() {
        return option != null && option.getZIndex() != null ? option.getZIndex() : 0;
    }

    /**
     * 获取系列数据
     * 
     * @return 系列数据列表
     */
    @Override
    public List<Object> getData() {
        List<Object> result = new ArrayList<>();
        for (BarDataItem item : dataItems) {
            result.add(item.getValue());
        }
        return result;
    }

    /**
     * 设置坐标系
     * 
     * @param coordinateSystem 坐标系
     */
    @Override
    public void setCoordinateSystem(CoordinateSystem coordinateSystem) {
        this.coordinateSystem = coordinateSystem;
    }

    /**
     * 获取坐标系
     * 
     * @return 坐标系
     */
    @Override
    public CoordinateSystem getCoordinateSystem() {
        return coordinateSystem;
    }
} 